define(['map3d.Net'], function (Net) {

    var ReqAsync = Net.ReqAsync;

    /**
     * @author mrdoob / http://mrdoob.com/
     */

    const Cache = THREE.Cache;
    const DefaultLoadingManager = THREE.DefaultLoadingManager;

    // import {Cache} from './Cache.js';
    // import {DefaultLoadingManager} from './LoadingManager.js';

    var loading = {};

    function FileLoader(manager) {

        this.manager = (manager !== undefined) ? manager : DefaultLoadingManager;

    }

    Object.assign(FileLoader.prototype, {

        load: function (url, onLoad, onProgress, onError) {

            if (url === undefined) url = '';

            if (this.path !== undefined) url = this.path + url;

            url = this.manager.resolveURL(url);

            var scope = this;

            var cached = Cache.get(url);

            if (cached !== undefined) {

                scope.manager.itemStart(url);

                setTimeout(function () {

                    if (onLoad) onLoad(cached);

                    scope.manager.itemEnd(url);

                }, 0);

                return cached;

            }

            // Check if request is duplicate

            if (loading[url] !== undefined) {

                loading[url].push({

                    onLoad: onLoad,
                    onProgress: onProgress,
                    onError: onError

                });

                return;

            }

            // Check for data: URI
            var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
            var dataUriRegexResult = url.match(dataUriRegex);

            // Safari can not handle Data URIs through XMLHttpRequest so process manually
            if (dataUriRegexResult) {

                var mimeType = dataUriRegexResult[1];
                var isBase64 = !!dataUriRegexResult[2];
                var data = dataUriRegexResult[3];

                data = window.decodeURIComponent(data);

                if (isBase64) data = window.atob(data);

                try {

                    var response;
                    var responseType = (this.responseType || '').toLowerCase();

                    switch (responseType) {

                        case 'arraybuffer':
                        case 'blob':

                            var view = new Uint8Array(data.length);

                            for (var i = 0; i < data.length; i++) {

                                view[i] = data.charCodeAt(i);

                            }

                            if (responseType === 'blob') {

                                response = new Blob([view.buffer], {type: mimeType});

                            } else {

                                response = view.buffer;

                            }

                            break;

                        case 'document':

                            var parser = new DOMParser();
                            response = parser.parseFromString(data, mimeType);

                            break;

                        case 'json':

                            response = JSON.parse(data);

                            break;

                        default: // 'text' or other

                            response = data;

                            break;

                    }

                    // Wait for next browser tick like standard XMLHttpRequest event dispatching does
                    window.setTimeout(function () {

                        if (onLoad) onLoad(response);

                        scope.manager.itemEnd(url);

                    }, 0);

                } catch (error) {

                    // Wait for next browser tick like standard XMLHttpRequest event dispatching does
                    window.setTimeout(function () {

                        if (onError) onError(error);

                        scope.manager.itemEnd(url);
                        scope.manager.itemError(url);

                    }, 0);

                }

            } else {

                // Initialise array for duplicate requests

                loading[url] = [];

                loading[url].push({

                    onLoad: onLoad,
                    onProgress: onProgress,
                    onError: onError

                });

                /*
                 * Callbacks
                 */
                var onProgressCallback = function (event) {

                    var callbacks = loading[url];

                    for (var i = 0, il = callbacks.length; i < il; i++) {

                        var callback = callbacks[i];
                        if (callback.onProgress) callback.onProgress(event);

                    }

                };

                var onErrorCallback = function (event) {

                    var callbacks = loading[url];

                    delete loading[url];

                    for (var i = 0, il = callbacks.length; i < il; i++) {

                        var callback = callbacks[i];
                        if (callback.onError) callback.onError(event);

                    }

                    scope.manager.itemEnd(url);
                    scope.manager.itemError(url);

                }

                var onFinishCallback = function (response) {

                    Cache.add(url, response);

                    var callbacks = loading[url];

                    delete loading[url];

                    // Some browsers return HTTP Status 0 when using non-http protocol
                    // e.g. 'file://' or 'data://'. Handle as success.

                    if (this.status === 0) console.warn('THREE.FileLoader: HTTP Status 0 received.');

                    for (var i = 0, il = callbacks.length; i < il; i++) {
                        var callback = callbacks[i];
                        if (callback.onLoad) callback.onLoad(response);
                    }

                    scope.manager.itemEnd(url);
                };

                /*
                 * Async Calls
                 */
                var reqOpts = {
                    method: 'GET',
                };

                if (this.responseType !== undefined) reqOpts.responseType = this.responseType;
                if (this.withCredentials !== undefined) reqOpts.withCredentials = this.withCredentials;
                // if (request.overrideMimeType) request.overrideMimeType(this.mimeType !== undefined ? this.mimeType : 'text/plain');
                if (this.requestHeader) {
                    var headerList = [];
                    for (var h in this.requestHeader) {
                        headerList.push([h, this.requestHeader[h]]);
                    }
                    reqOpts.headers = headerList;
                }

                var request = ReqAsync(url, reqOpts, onFinishCallback, onProgressCallback, onErrorCallback);

                /*
                 * Original Sync Calls
                 */

                // var request = new XMLHttpRequest();
                //
                // request.open('GET', url, true);
                //
                // request.addEventListener('load', function (event) {
                //
                //     var response = this.response;
                //
                //     Cache.add(url, response);
                //
                //     var callbacks = loading[url];
                //
                //     delete loading[url];
                //
                //     if (this.status === 200 || this.status === 0) {
                //
                //         // Some browsers return HTTP Status 0 when using non-http protocol
                //         // e.g. 'file://' or 'data://'. Handle as success.
                //
                //         if (this.status === 0) console.warn('THREE.FileLoader: HTTP Status 0 received.');
                //
                //         for (var i = 0, il = callbacks.length; i < il; i++) {
                //
                //             var callback = callbacks[i];
                //             if (callback.onLoad) callback.onLoad(response);
                //
                //         }
                //
                //         scope.manager.itemEnd(url);
                //
                //     } else {
                //
                //         for (var i = 0, il = callbacks.length; i < il; i++) {
                //
                //             var callback = callbacks[i];
                //             if (callback.onError) callback.onError(event);
                //
                //         }
                //
                //         scope.manager.itemEnd(url);
                //         scope.manager.itemError(url);
                //
                //     }
                //
                // }, false);
                //
                // request.addEventListener('progress', onProgressCallback, false);
                //
                // request.addEventListener('error', onErrorCallback, false);
                //
                // if (this.responseType !== undefined) request.responseType = this.responseType;
                // if (this.withCredentials !== undefined) request.withCredentials = this.withCredentials;
                //
                // if (request.overrideMimeType) request.overrideMimeType(this.mimeType !== undefined ? this.mimeType : 'text/plain');
                //
                // for (var header in this.requestHeader) {
                //
                //     request.setRequestHeader(header, this.requestHeader[header]);
                //
                // }
                //
                // request.send(null);

            }

            scope.manager.itemStart(url);

            return request;

        },

        setPath: function (value) {

            this.path = value;
            return this;

        },

        setResponseType: function (value) {

            this.responseType = value;
            return this;

        },

        setWithCredentials: function (value) {

            this.withCredentials = value;
            return this;

        },

        setMimeType: function (value) {

            this.mimeType = value;
            return this;

        },

        setRequestHeader: function (value) {

            this.requestHeader = value;
            return this;

        }

    });

    THREE.FileLoader = FileLoader;

    return FileLoader;

});